import time
import uuid
import json
from multiprocessing import Lock
import os


if os.name == "posix":
    tmp_dir = "/tmp"
else:
    os.makedirs("tmp", exist_ok=True)
    tmp_dir = "tmp"


class USharedList:
    """
    此共享列表用于进程间共享数据，以文件传递方式实现，自带进程锁，适应于更新不太频繁的场景，高并发的传递消息场景不适合
    """
    def __init__(self, file: str = None):
        """
        此共享列表用于进程间共享数据，以文件传递方式实现，自带进程锁，适应于更新不太频繁的场景，高并发的传递消息场景不适合
        :param file: 用于持久化数据的文件名，不指定时自动在tmp目录中生成一个临时文件
        """
        if file is None:
            file = os.path.join(tmp_dir, f"shared_list_{uuid.uuid4()}.json")
        self.file = file

        self.lock = Lock()
        self.write(list())


    def write(self, data):
        with self.lock:
            with open(self.file, "w") as f:
                json.dump(data, f)
            with open(self.file + ".bak", "w") as f:
                json.dump(data, f)

    def _write(self, data):
        with open(self.file, "w") as f:
            json.dump(data, f)
        with open(self.file + ".bak", "w") as f:
            json.dump(data, f)

    def read(self):
        try:
            with open(self.file, "r") as f:
                data = json.load(f)
        except json.JSONDecodeError:
            try:
                with open(self.file + ".bak", "r") as f:
                    data = json.load(f)
            except json.JSONDecodeError:
                data = list()
        return data

    def pop(self, __index=-1):
        with self.lock:
            data = self.read()
            if not isinstance(data, list):
                raise SyntaxError(f"{type(data)} is not a list, do not support pop function")
            data.pop(__index)
            self._write(data)

    def insert(self, __index, __object):
        with self.lock:
            data = self.read()
            if not isinstance(data, list):
                raise SyntaxError(f"{type(data)} is not a list, do not support insert function")
            data.insert(__index, __object)
            self._write(data)

    def append(self, __object):
        with self.lock:
            data = self.read()
            if not isinstance(data, list):
                raise SyntaxError(f"{type(data)} is not a list, do not support append function")
            data.append(__object)
            self._write(data)

    def remove(self, __value):
        with self.lock:
            data = self.read()
            if not isinstance(data, list):
                raise SyntaxError(f"{type(data)} is not a list, do not support remove function")
            data.remove(__value)
            self._write(data)

    def clear(self):
        self.write(list())

    def __bool__(self):
        data = self.read()
        return bool(len(data))

    def __contains__(self, y):  # real signature unknown; restored from __doc__
        """ x.__contains__(y) <==> y in x. """
        data = self.read()
        return y in data

    def __del__(self):
        os.remove(self.file)

    def __str__(self):
        data = self.read()
        return str(data)

    def __getitem__(self, __index): # real signature unknown; restored from __doc__
        """ x.__getitem__(y) <==> x[y] """
        data = self.read()
        if not isinstance(data, list):
            raise SyntaxError(f"{type(data)} is not a list, do not support __getitem__ function")
        return data[__index]

    def __setitem__(self, __index, value):
        with self.lock:
            data = self.read()
            if not isinstance(data, list):
                raise SyntaxError(f"{type(data)} is not a list, do not support __setitem__ function")
            data[__index] = value
            self._write(data)


class USharedDict:
    """
    此共享字典用于进程间共享数据，以文件传递方式实现，自带进程锁，适应于更新不太频繁的场景，高并发的传递消息场景不适合
    """
    def __init__(self, file: str = None):
        """
        此共享字典用于进程间共享数据，以文件传递方式实现，自带进程锁，适应于更新不太频繁的场景，高并发的传递消息场景不适合
        :param file: 用于持久化数据的文件名，不指定时自动在tmp目录中生成一个临时文件
        """
        if file is None:
            file = os.path.join(tmp_dir, f"shared_dict_{uuid.uuid4()}.json")
        self.file = file

        self.lock = Lock()
        self.write(dict())

    def write(self, data):
        with self.lock:
            with open(self.file, "w") as f:
                json.dump(data, f)
            with open(self.file + ".bak", "w") as f:
                json.dump(data, f)

    def _write(self, data):
        with open(self.file, "w") as f:
            json.dump(data, f)
        with open(self.file + ".bak", "w") as f:
            json.dump(data, f)

    def read(self):
        try:
            with open(self.file, "r") as f:
                data = json.load(f)
        except json.JSONDecodeError:
            try:
                with open(self.file + ".bak", "r") as f:
                    data = json.load(f)
            except json.JSONDecodeError:
                data = dict()
        return data

    def pop(self, __key):
        with self.lock:
            data = self.read()
            if not isinstance(data, dict):
                raise SyntaxError(f"{type(data)} is not a dict, do not support pop function")
            data.pop(__key)
            self._write(data)

    def __getitem__(self, y): # real signature unknown; restored from __doc__
        """ x.__getitem__(y) <==> x[y] """
        data = self.read()
        if not isinstance(data, dict):
            raise SyntaxError(f"{type(data)} is not a dict, do not support get function")
        return data.get(y)

    def __setitem__(self, key, value):
        with self.lock:
            data = self.read()
            if not isinstance(data, dict):
                raise SyntaxError(f"{type(data)} is not a dict, do not support __setitem__ function")
            data[key] = value
            self._write(data)

    def get(self, y, __default): # real signature unknown; restored from __doc__
        """ x.__getitem__(y) <==> x[y] """
        data = self.read()
        if not isinstance(data, dict):
            raise SyntaxError(f"{type(data)} is not a dict, do not support get function")
        return data.get(y, __default)

    def items(self): # real signature unknown; restored from __doc__
        """ D.items() -> a set-like object providing a view on D's items """
        data = self.read()
        if not isinstance(data, dict):
            raise SyntaxError(f"{type(data)} is not a dict, do not support items function")
        return data.items()

    def keys(self): # real signature unknown; restored from __doc__
        """ D.keys() -> a set-like object providing a view on D's keys """
        data = self.read()
        if not isinstance(data, dict):
            raise SyntaxError(f"{type(data)} is not a dict, do not support keys function")
        return data.keys()

    def values(self): # real signature unknown; restored from __doc__
        """ D.keys() -> a set-like object providing a view on D's keys """
        data = self.read()
        if not isinstance(data, dict):
            raise SyntaxError(f"{type(data)} is not a dict, do not support values function")
        return data.values()

    def __delitem__(self, key):
        with self.lock:
            data = self.read()
            if not isinstance(data, dict):
                raise SyntaxError(f"{type(data)} is not a dict, do not support __delitem__ function")
            data.__delitem__(key)
            self._write(data)

    def clear(self):
        self.write(dict())

    def __bool__(self):
        data = self.read()
        return bool(len(data))

    def __contains__(self, y):  # real signature unknown; restored from __doc__
        """ x.__contains__(y) <==> y in x. """
        data = self.read()
        return y in data

    def __del__(self):
        if os.path.exists(self.file):
            os.remove(self.file)

    def __str__(self):
        data = self.read()
        return str(data)


if __name__ == "__main__":
    a = USharedList()
    a.append(1)
    print(a)
    a[0] = 2
    print(3 in a)
    print(a)
    a.clear()
    time.sleep(5)